Correction du Sujet 05 - NSI 2026 (Jour 1)

Exercice 1 : Tri, arbre binaire de recherche et programmation orientée objet

Partie A : Dictionnaire et tri

1) Calcul du score total de l'athlète Alex
Les points obtenus sont :
Le score total d'Alex est donc : 454 points.
2) Fonction nb_points complétée
def nb_points(epreuve, valeur):
    points = 0
    if epreuve == '100m':
        points = (20 - valeur) * 10
    elif epreuve == 'longueur':
        points = valeur * 20
    elif epreuve == 'poids':
        points = valeur * 10
    elif epreuve == '1500m':
        points = 500 - valeur
    return points
3) Fonction score complétée
def score(athlete):
    total = 0
    performances = athlete['performances']
    for epreuve in performances:
        valeur = performances[epreuve]
        total += nb_points(epreuve, valeur)
    athlete['score'] = total
4) Complétion de la ligne 6 de la fonction classer
def classer(l):
    n = len(l)
    for i in range(n):
        max_index = i
        for j in range(i + 1, n):
            if l[j]['score'] > l[max_index]['score']:
                max_index = j
        temp = l[i]
        l[i] = l[max_index]
        l[max_index] = temp
5) Type de tri effectué par la fonction classer
La fonction cherche, à chaque étape, le meilleur élément restant, puis l'échange avec l'élément placé à l'indice courant. Il s'agit donc d'un tri par sélection.
6) Coût de la fonction classer
Pour une liste de taille n, le nombre de comparaisons est :

(n - 1) + (n - 2) + ... + 1 + 0 = n(n - 1) / 2.

Le coût en nombre de comparaisons est donc n(n - 1) / 2, soit un coût quadratique.

Partie B : Arbre binaire de recherche

7) Création de l'objet alex
alex = Athlete('Alex', 13.0, 5.2, 9.0, 310.0)
8) Code de la méthode calculer_score
def calculer_score(self):
    points_100m = (20 - self.m100) * 10
    points_longueur = self.longueur * 20
    points_poids = self.poids * 10
    points_1500m = 500 - self.m1500
    return points_100m + points_longueur + points_poids + points_1500m
9) Arbre obtenu après insertion des six athlètes
Les scores plus petits sont placés dans le sous-arbre gauche et les scores plus grands ou égaux dans le sous-arbre droit.

Martin (354) / \ Lena (351) Yanis (355) / \ \ Rayan (350) Ninon (351) Ana (356)
10) Méthode inserer complétée
def inserer(self, athlete):
    if athlete.score < self.valeur.score:
        if self.gauche == None:
            self.gauche = Noeud(athlete)
        else:
            self.gauche.inserer(athlete)
    else:
        if self.droite == None:
            self.droite = Noeud(athlete)
        else:
            self.droite.inserer(athlete)
11) Type de parcours utilisé dans la méthode classer
La méthode réalise un parcours infixe inversé : on parcourt d'abord le sous-arbre droit, puis le nœud courant, puis le sous-arbre gauche.

Dans cet arbre binaire de recherche, les scores les plus grands sont à droite et les scores les plus petits à gauche. Ce parcours permet donc d'obtenir les athlètes dans l'ordre décroissant de leur score.
12) Avantages et inconvénients des deux approches
Approche Avantage Inconvénient
Dictionnaires et tri Approche simple, facile à lire et adaptée à une petite liste. Avec le tri par sélection proposé, le coût est quadratique : le classement devient moins efficace quand la liste grandit.
Arbre binaire de recherche et objets Approche structurée, pratique pour insérer progressivement des athlètes et obtenir ensuite un classement par parcours. Le code est plus complexe, et si l'arbre est déséquilibré, les performances peuvent devenir mauvaises.

Exercice 2 : Sécurisation des communications et programmation

1) Déchiffrement du message donné
En lisant la grille fournie :
Le message déchiffré est donc : CODE.
2) Chiffrement du message BAC avec la clé SECURITY1024
Avec la clé SECURITY1024, l'ordre d'insertion est :
SECURITY1024ABDFGHJKLMNOPQVWXZ356789.

La grille obtenue est :
123456
1SECURI
2TY1024
3ABDFGH
4JKLMNO
5PQVWXZ
6356789
On obtient donc : BAC = (3, 2) (3, 1) (1, 3).
3) Pourquoi le chiffrement de Polybe est symétrique
Le chiffrement de Polybe est symétrique car la même clé, donc la même grille, sert à chiffrer et à déchiffrer le message. Alice et Bob doivent donc connaître la même clé secrète.
4) Résultat de generer_ordre('AXU7')
AXU7BCDEFGHIJKLMNOPQRSTVWYZ012345689
5) Fonction grille_vide
def grille_vide(n):
    return [['' for _ in range(n)] for _ in range(n)]
6) Fonction generer_grille complétée
def generer_grille(cle):
    ordre_insertion = generer_ordre(cle)
    grille = grille_vide(6)
    indice = 0
    for i in range(6):
        for j in range(6):
            grille[i][j] = ordre_insertion[indice]
            indice = indice + 1
    return grille
7) Fonction dechiffrer complétée
def dechiffrer(cle, message):
    resultat = ''
    grille = generer_grille(cle)
    for t in message:
        resultat = resultat + grille[t[0] - 1][t[1] - 1]
    return resultat
8) Fonction generer_dico
def generer_dico(cle):
    grille = generer_grille(cle)
    dico = {}
    for i in range(6):
        for j in range(6):
            dico[grille[i][j]] = (i + 1, j + 1)
    return dico
9) Fonction chiffrer
def chiffrer(cle, message):
    dico = generer_dico(cle)
    resultat = []
    for caractere in message:
        resultat.append(dico[caractere])
    return resultat
10) Différence entre chiffrement symétrique et asymétrique
Un algorithme de chiffrement symétrique utilise la même clé pour chiffrer et pour déchiffrer.

Un algorithme de chiffrement asymétrique utilise deux clés différentes : une clé publique et une clé privée. La clé publique peut servir à chiffrer un message destiné à une personne, et seule sa clé privée permet ensuite de le déchiffrer.

Exercice 3 : Programmation orientée objet, récursivité et bases de données

Partie A : La classe Demineur

1) Assertion sur le pourcentage de mines
assert 0.10 <= pourcentage_mines <= 0.30, 'Le pourcentage de mines doit être compris entre 10% et 30%.'
2) Complétion des attributs du constructeur
self.hauteur = hauteur
self.largeur = largeur
self.pourcentage_mines = pourcentage_mines
3) Création d'une instance pour le niveau intermédiaire
demineur_intermediaire = Demineur(16, 16, 0.156)

Partie B : Création de la grille du démineur

4) Méthode grille_demineur_vide
def grille_demineur_vide(self):
    return [[0 for _ in range(self.largeur)] for _ in range(self.hauteur)]
5) Méthode placer_mines complétée
def placer_mines(self):
    compteur_mines = 0
    nombre_bombes = self.largeur * self.hauteur * self.pourcentage_mines
    while compteur_mines < nombre_bombes:
        ligne = randint(0, self.hauteur - 1)
        colonne = randint(0, self.largeur - 1)
        if self.grille_demineur[ligne][colonne] == 0:
            self.grille_demineur[ligne][colonne] = -1
            compteur_mines = compteur_mines + 1
6) Méthode nombre_voisines_avec_mines
def nombre_voisines_avec_mines(self, coordonnees_case):
    compteur = 0
    for case in self.voisines(coordonnees_case):
        ligne, colonne = case
        if self.grille_demineur[ligne][colonne] == -1:
            compteur = compteur + 1
    return compteur
7) Méthode generer_demineur
def generer_demineur(self):
    self.placer_mines()
    for ligne in range(self.hauteur):
        for colonne in range(self.largeur):
            if self.grille_demineur[ligne][colonne] != -1:
                self.grille_demineur[ligne][colonne] = self.nombre_voisines_avec_mines((ligne, colonne))

Partie C : L'interface utilisateur du jeu du démineur

8) Méthode visibilite
def visibilite(self, coordonnees_case):
    ligne, colonne = coordonnees_case
    if self.grille_demineur[ligne][colonne] == -1:
        for i in range(self.hauteur):
            for j in range(self.largeur):
                self.grille_visibilite[i][j] = True
    else:
        if not self.grille_visibilite[ligne][colonne]:
            self.grille_visibilite[ligne][colonne] = True
            if self.grille_demineur[ligne][colonne] == 0:
                for case in self.voisines(coordonnees_case):
                    i, j = case
                    if not self.grille_visibilite[i][j]:
                        self.visibilite(case)

Partie D : Jouer en ligne au démineur

9) Clés étrangères de la table Meilleur_score
La table Meilleur_score possède deux clés étrangères :
10) Requête permettant d'obtenir le tableau niveau / score
SELECT niveau, score
FROM Meilleur_score
JOIN Joueur ON Joueur.id_joueur = Meilleur_score.joueur
WHERE pseudo = 'Raptor';
11) Mise à jour du mot de passe de Kirna
UPDATE Joueur
SET mot_de_passe = 'cGhhxDE4'
WHERE pseudo = 'Kirna';
12) Résultat de la requête donnée
La requête cherche les joueurs ayant un score strictement supérieur à 1000 au niveau expert avec un temps strictement inférieur à 400.

Seul Raptor vérifie ces conditions :
pseudo
Raptor
13) Requêtes pour corriger le niveau facile en débutant
Il faut corriger le nom du niveau dans la table Demineur et aussi dans la table Meilleur_score où ce niveau peut être référencé.
UPDATE Demineur
SET niveau = 'débutant'
WHERE niveau = 'facile';

UPDATE Meilleur_score
SET niveau = 'débutant'
WHERE niveau = 'facile';
Si la base impose strictement la contrainte de clé étrangère sans mise à jour en cascade, on peut effectuer cette correction dans une transaction adaptée ou créer d'abord le nouveau niveau avant de modifier les scores associés.